#include "GLCommon.h"
#include <stdlib.h>

namespace simple_renderer {

static const GLfloat g_bt709[] = {
        1.164,  1.164,  1.164,
        0.0,   -0.213,  2.112,
        1.793, -0.533,  0.0,
};
const GLfloat *GLES2_getColorMatrix_bt709()
{
    return g_bt709;
}

static const GLfloat g_bt601[] = {
        1.164,  1.164, 1.164,
        0.0,   -0.392, 2.017,
        1.596, -0.813, 0.0,
};
const GLfloat *GLES2_getColorMatrix_bt601()
{
    return g_bt601;
}

void GLES2_checkError(const char* op) {
    for (GLint error = glGetError(); error; error = glGetError()) {
        LOGE("[GLES2] after %s() glError (0x%x)\n", op, error);
    }
}

void GLES2_printString(const char *name, GLenum s) {
    const char *v = (const char *) glGetString(s);
    LOGI("[GLES2] %s = %s\n", name, v);
}

void GLES2_printShaderInfo(GLuint shader)
{
    if (!shader)
        return;

    GLint info_len = 0;
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_len);
    if (!info_len) {
        LOGE("[GLES2][Shader] empty info\n");
        return;
    }

    char    buf_stack[32];
    char   *buf_heap = nullptr;
    char   *buf      = buf_stack;
    GLsizei buf_len  = sizeof(buf_stack) - 1;
    if (info_len > sizeof(buf_stack)) {
        buf_heap = (char*) malloc(info_len + 1);
        if (buf_heap) {
            buf     = buf_heap;
            buf_len = info_len;
        }
    }

    glGetShaderInfoLog(shader, buf_len, nullptr, buf);
    LOGE("[GLES2][Shader] error %s\n", buf);

    if (buf_heap)
        free(buf_heap);
}

GLuint GLES2_loadShader(GLenum shader_type, const char *shader_source)
{
    assert(shader_source);

    GLuint shader = glCreateShader(shader_type);        GLES2_checkError("glCreateShader");
    if (!shader)
        return 0;

    assert(shader_source);

    glShaderSource(shader, 1, &shader_source, nullptr);    GLES2_checkError("glShaderSource");
    glCompileShader(shader);                            GLES2_checkError("glCompileShader");

    GLint compile_status = 0;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
    if (!compile_status)
        goto fail;

    return shader;

    fail:

    if (shader) {
        GLES2_printShaderInfo(shader);
        glDeleteShader(shader);
    }

    return 0;
}

void GLES2_printProgramInfo(GLuint program)
{
    if (!program)
        return;

    GLint info_len = 0;
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_len);
    if (!info_len) {
        LOGE("[GLES2][Program] empty info\n");
        return;
    }

    char    buf_stack[32];
    char   *buf_heap = nullptr;
    char   *buf      = buf_stack;
    GLsizei buf_len  = sizeof(buf_stack) - 1;
    if (info_len > sizeof(buf_stack)) {
        buf_heap = (char*) malloc(info_len + 1);
        if (buf_heap) {
            buf     = buf_heap;
            buf_len = info_len;
        }
    }

    glGetProgramInfoLog(program, buf_len, nullptr, buf);
    LOGE("[GLES2][Program] error %s\n", buf);

    if (buf_heap)
        free(buf_heap);
}

}